package cn.xyh.filter;

import cn.xyh.exception.RoleException;
import cn.xyh.model.User;
import cn.xyh.service.IRoleService;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * @author zhumin
 * @ClassName: UrlShiroAccessFilter
 * @Description: URL权限拦截
 * @date 2016年8月3日 下午3:31:20
 */
public class UrlShiroAccessFilter extends AccessControlFilter {


    private static Logger LOG = Logger.getLogger(UrlShiroAccessFilter.class.getName());

    //转发状态码
    public static final int STATUS_NEED_LOGIN_FIRST = 701;
    public static final int STATUS_RESOURCE_NOT_FOUND = 702;
    public static final int STATUS_NO_PERMISSION = 707;

    @Autowired
    private IRoleService roleService;


    @Override
    protected boolean isAccessAllowed(ServletRequest req, ServletResponse resp, Object mappedValue)
            throws Exception {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        String url = request.getRequestURI();
        LOG.debug("preHandle =" + url + " request method = " + request.getMethod());
        boolean flag = true;
        Subject user = SecurityUtils.getSubject();

        if (!user.isAuthenticated()) {
            forward("很抱歉，需要先登录。", request, response, STATUS_NEED_LOGIN_FIRST);
            flag = false;
            return flag;
        }

        try {
            //1、验证url权限
            String shiroUrl = getRequestPath(request);
            System.out.println("待验证的url: " + shiroUrl);

            //1-1 拿到资源集合如果存在session则从session中取得.
            User shiroUser = (User) user.getPrincipals().getPrimaryPrincipal();
            List<Long> roleList = shiroUser.roleList;

            Set<String> urlSet = (Set<String>) request.getSession().getAttribute("urls");
            if (urlSet == null) {
                urlSet = new HashSet<String>();
                for (Long roleId : roleList) {
                    System.out.println(roleId);
                    List<Map<Long, String>> roleResourceList = roleService.findRoleResourceListByRoleId(roleId);
                    if (roleResourceList != null) {
                        for (Map<Long, String> map : roleResourceList) {
                            if (StringUtils.isNotBlank(map.get("url_path"))) {
                                urlSet.add(map.get("url_path"));
                            }
                        }
                    }
                }
                request.getSession().setAttribute("urls", urlSet);
            }
            //1-2 循环匹配资源集合
            boolean accessFlag = false;
            for (String urls : urlSet) {
                if (urls.indexOf(":") > -1) {
                    String[] splitS = urls.split(":");
                    for (String vo : splitS) {
                        if (shiroUrl.contains(vo)) {
                            accessFlag = true;
                            break;
                        }
                    }
                } else {
                    if (shiroUrl.contains(urls)) {
                        accessFlag = true;
                        break;
                    }
                }
            }
            if (accessFlag) {
                flag = true;
                return flag;
            } else {
                String msg = "<span style='color:red;'>没有访问权限。</span><br/><br/>当前用户：" + user.getPrincipal().toString();
                forward(msg, request, response, STATUS_NO_PERMISSION);
                flag = false;
                return flag;
            }
        } catch (RoleException e) {
            flag = false;
            e.printStackTrace();
        }
        return flag;

    }


    private void forward(String msg, HttpServletRequest request, HttpServletResponse response, int type)
            throws IOException {
        System.out.println("forward ~ " + msg);

        //如果是ajax请求，那么直接返回对应的错误信息
        // request from ajax method
        if (request.getHeader("x-requested-with") != null
                && request.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest")) {
            response.setHeader("sessionstatus", "timeout");
            response.setContentType("text/html; charset=UTF-8");
            PrintWriter out = response.getWriter();
            //if(request.getQueryString())

            //对于没有?xxx的Ajax请求，直接打印消息
            if (request.getQueryString() == null) {
                out.println(msg);
                out.flush();
                out.close();
                return;
            }

//            if(request.getQueryString().indexOf("type=validform") != -1){
//                if(type == STATUS_RESOURCE_NOT_FOUND){
//                    ValidFormJSON vfjson = new ValidFormJSON();
//                    vfjson.setStatus("n");
//                    vfjson.setInfo("很抱歉，资源不存在！");
//                    out.println(com.alibaba.fastjson.JSON.toJSONString(vfjson));
//                }else if(type == STATUS_NO_PERMISSION){
//                    ValidFormJSON vfjson = new ValidFormJSON();
//                    vfjson.setStatus("n");
//                    vfjson.setInfo("很抱歉，没有权限！");
//                    out.println(com.alibaba.fastjson.JSON.toJSONString(vfjson));
//                }else if(type == STATUS_NEED_LOGIN_FIRST){
//                    ValidFormJSON vfjson = new ValidFormJSON();
//                    vfjson.setStatus("n");
//                    vfjson.setInfo("请先登录！");
//                    out.println(com.alibaba.fastjson.JSON.toJSONString(vfjson));
//                }else{
//                    ValidFormJSON vfjson = new ValidFormJSON();
//                    vfjson.setStatus("n");
//                    vfjson.setInfo("很抱歉，未知错误！");
//                    out.println(com.alibaba.fastjson.JSON.toJSONString(vfjson));
//                }
//            }else{
            out.println(msg);
//            }

            out.flush();
            out.close();
            return;
        }

        //701 未登陆
        if (STATUS_NEED_LOGIN_FIRST == type) {
            LOG.debug("response committed ~ " + response.isCommitted());
//            WebUtils.redirectToSavedRequest(request, response, request.getContextPath());
            response.sendRedirect("/user/toLogin.do");
            return;
        }
        //如果是550错误，那么转向/error/nopermission
        //因为/error/nopermission也找不到，所以继续会重定向到这个，形成循环重定向问题
        if (STATUS_NO_PERMISSION == type) { // no permission
//            response.sendRedirect(request.getContextPath() + "/error/nopermission");

            response.setContentType("text/html; charset=UTF-8");
            PrintWriter out = response.getWriter();
            String shiroUrl = getRequestPath(request);
            out.println("<span style='color:red'>[" + shiroUrl + "]您没有访问权限</span>");

            out.flush();
            out.close();

            return;
        }

        //702 资源没有配置
        if (STATUS_RESOURCE_NOT_FOUND == type) {
            response.setContentType("text/html; charset=UTF-8");
            PrintWriter out = response.getWriter();
            String shiroUrl = getRequestPath(request);
            out.println("<span style='color:red'>[" + shiroUrl + "]资源没有配置</span>");

            out.flush();
            out.close();
            return;
        }

        //如果都不是，转向首页
        response.sendRedirect(request.getContextPath());
    }


    /**
     * 获得请求路径
     *
     * @param request
     * @return
     */
    private String getRequestPath(HttpServletRequest request) {
        String requestPath = request.getRequestURI();
        if (request.getQueryString() != null) {

            requestPath += "?" + request.getQueryString();
        }
        if (requestPath.indexOf("&") > -1) {// 去掉其他参数
            requestPath = requestPath.substring(0, requestPath.indexOf("&"));
        }
        requestPath = requestPath.substring(request.getContextPath().length());// 去掉项目路径

        //下面这句代码，是对?id=xx的字符串进行替换，而?edit这种字符串则不替换
        // requestPath = regexReplace(requestPath, "[\\?]*([0-9a-zA-Z]*=[0-9a-zA-Z\\-]*)", "");


        //去掉第二个反斜杠后的内容以模糊匹配数据库的url权限.
/*       if(requestPath.indexOf("/",2) > -1){
          requestPath = requestPath.substring(0, requestPath.indexOf("/",2));
       }*/


        return requestPath;
    }

    private String regexReplace(String content, String search, String replacement) {
        Pattern p = Pattern.compile(search);
        Matcher m = p.matcher(content);
        String s = m.replaceAll(replacement);
        return s;
    }


    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        return false;
    }
}